﻿namespace iFinance.Controls
{
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;

    /// <summary>
    /// 带输入验证功能的输入控件
    /// </summary>
    [TemplatePart(Name = "PART_DisplayName", Type = typeof(Label))]
    [TemplatePart(Name = "PART_Input", Type = typeof(ContentPresenter))]
    [TemplatePart(Name = "PART_Description", Type = typeof(DescriptionViewer))]
    public class ValidationInput : Control
    {
        public ValidationInput()
        {
            this.DefaultStyleKey = typeof(ValidationInput);
        }

        #region Property

        private Label displayNameLabel = null;
        private ContentPresenter inputContent = null;
        private DescriptionViewer descriptionViewer = null;

        /// <summary>
        /// 实际的输入控件
        /// </summary>
        public FrameworkElement Input { get; set; }

        [Category("ValidationInput")]
        [Description("显示名的宽度")]
        public double DisplayNameWidth
        {
            get { return (double)GetValue(DisplayNameWidthProperty); }
            set { SetValue(DisplayNameWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DisplayNameWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisplayNameWidthProperty =
            DependencyProperty.Register("DisplayNameWidth", typeof(double), typeof(ValidationInput), new PropertyMetadata(double.NaN));

        [Category("ValidationInput")]
        [Description("显示名的高度")]
        public double DisplayNameHeight
        {
            get { return (double)GetValue(DisplayNameHeightProperty); }
            set { SetValue(DisplayNameHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DisplayNameHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisplayNameHeightProperty =
            DependencyProperty.Register("DisplayNameHeight", typeof(double), typeof(ValidationInput), new PropertyMetadata(double.NaN));

        [Category("ValidationInput")]
        [Description("输入控件的宽度")]
        public double InputWidth
        {
            get { return (double)GetValue(InputWidthProperty); }
            set { SetValue(InputWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for InputWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InputWidthProperty =
            DependencyProperty.Register("InputWidth", typeof(double), typeof(ValidationInput), new PropertyMetadata(double.NaN));

        [Category("ValidationInput")]
        [Description("输入控件的高度")]
        public double InputHeight
        {
            get { return (double)GetValue(InputHeightProperty); }
            set { SetValue(InputHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for InputHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InputHeightProperty =
            DependencyProperty.Register("InputHeight", typeof(double), typeof(ValidationInput), new PropertyMetadata(double.NaN));

        [Category("ValidationInput")]
        [Description("验证控件的类型")]
        public ValidationInputType Type
        {
            get { return (ValidationInputType)GetValue(TypeProperty); }
            set { SetValue(TypeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Type.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TypeProperty =
            DependencyProperty.Register("Type", typeof(ValidationInputType), typeof(ValidationInput), new PropertyMetadata(ValidationInputType.TextBox));

        [Category("ValidationInput")]
        [Description("显示名")]
        public string DisplayName
        {
            get { return (string)GetValue(DisplayNameProperty); }
            set { SetValue(DisplayNameProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DisplayName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisplayNameProperty =
            DependencyProperty.Register("DisplayName", typeof(string), typeof(ValidationInput), new PropertyMetadata(string.Empty, OnDisplayNameChanged));

        [Category("ValidationInput")]
        [Description("描述")]
        public string Description
        {
            get { return (string)GetValue(DescriptionProperty); }
            set { SetValue(DescriptionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Description.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DescriptionProperty =
            DependencyProperty.Register("Description", typeof(string), typeof(ValidationInput), new PropertyMetadata(string.Empty, OnDescriptionChanged));

        [Category("ValidationInput")]
        [Description("值")]
        public string Value
        {
            get { return (string)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(string), typeof(ValidationInput), new PropertyMetadata(string.Empty));

        #endregion

        #region Method

        public static void OnDisplayNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as ValidationInput).SetDisplayNameBinding();
        }

        public static void OnDescriptionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as ValidationInput).SetDescriptionBinding();
        }

        /// <summary>
        /// 绑定DisplayName
        /// </summary>
        private void SetDisplayNameBinding()
        {
            if (this.displayNameLabel != null)
            {
                var bindingExpression = this.GetBindingExpression(ValidationInput.DisplayNameProperty);
                if (bindingExpression != null)
                {
                    var binding = bindingExpression.ParentBinding;
                    this.displayNameLabel.SetBinding(Label.ContentProperty, binding);
                }
                else
                {
                    if (!string.IsNullOrEmpty(DisplayName))
                    {
                        this.displayNameLabel.Content = DisplayName;
                    }
                    else
                    {
                        this.displayNameLabel.SetValue(Label.TargetProperty, this.Input);
                    }
                }
            }
        }

        /// <summary>
        /// 绑定Description
        /// </summary>
        private void SetDescriptionBinding()
        {
            if (this.descriptionViewer != null)
            {
                var bindingExpression = this.GetBindingExpression(ValidationInput.DescriptionProperty);
                if (bindingExpression != null)
                {
                    var binding = bindingExpression.ParentBinding;
                    this.descriptionViewer.SetBinding(DescriptionViewer.DescriptionProperty, binding);
                }
                else
                {
                    if (!string.IsNullOrEmpty(Description))
                    {
                        this.descriptionViewer.Description = Description;
                    }
                    else
                    {
                        this.descriptionViewer.SetValue(DescriptionViewer.TargetProperty, this.Input);
                    }
                }
            }
        }

        /// <summary>
        /// 设置输入控件的绑定值，如果没有绑定则直接设置值
        /// </summary>
        /// <param name="property">要设置到的属性</param>
        private void SetInputBinding(DependencyProperty property)
        {
            var bindingExpression = this.GetBindingExpression(ValidationInput.ValueProperty);
            Binding binding = null;
            if (bindingExpression != null)
            {
                binding = bindingExpression.ParentBinding;
            }

            if (Input != null && binding != null)
            {
                Input.SetBinding(property, binding);
            }
            else
            {
                Input.SetValue(property, Value);
            }
        }

        /// <summary>
        /// 根据类型创建输入的控件
        /// </summary>
        private void CreateInputContent()
        {
            if (this.inputContent != null)
            {               
                switch (Type)
                {
                    case ValidationInputType.Password:
                        Input = new PasswordBox();
                        SetInputBinding(PasswordBox.PasswordProperty);
                        break;
                    case ValidationInputType.ComboBox:
                        break;
                    case ValidationInputType.CheckBox:
                        break;
                    case ValidationInputType.TextBox:
                    default:
                        Input = new TextBox();
                        SetInputBinding(TextBox.TextProperty);
                        break;
                }
                this.inputContent.Content = Input;
            }
        }

        #endregion

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this.displayNameLabel = base.GetTemplateChild("PART_DisplayName") as Label;
            this.inputContent = base.GetTemplateChild("PART_Input") as ContentPresenter;
            this.descriptionViewer = base.GetTemplateChild("PART_Description") as DescriptionViewer;

            //根据类型创建输入的控件
            CreateInputContent();
            //绑定DisplayName
            SetDisplayNameBinding();
            //绑定Description
            SetDescriptionBinding();
        }
    }
}
